/*!********************************************************************

  Audacity: A Digital Audio Editor

  @file EffectUIServices.h

  Paul Licameli split from EffectPlugin.h

**********************************************************************/
#ifndef __AUDACITY_EFFECT_UI_SERVICES__
#define __AUDACITY_EFFECT_UI_SERVICES__

#include "EffectInterface.h"
#include <memory>
#include <optional>

class EffectBase;
class EffectEditor;
class EffectInstance;
class EffectPlugin;
class EffectSettings;
class EffectOutputs;
class EffectUIServices;
class ShuttleGui;
class wxWindow;
class wxDialog;

using OptionalMessage
    =std::optional<std::unique_ptr<EffectSettingsAccess::Message> >;

struct DialogFactoryResults {
    wxDialog* pDialog{};
    //! constructed and successfully Init()-ed; or null for failure
    std::shared_ptr<EffectInstance> pInstance{};
    EffectEditor* pEditor{};
};

//! Type of function that creates a dialog for an effect
/*! The dialog may be modal or non-modal */
using EffectDialogFactory = std::function< DialogFactoryResults (
                                               wxWindow& parent, EffectBase&, EffectUIServices&,
                                               EffectSettingsAccess&) >;

//! Abstract base class to populate a UI and validate UI values.
//! It can import and export presets.
class AUDACITY_DLL_API EffectUIServices /* not final */
{
public:
    // Display a message box, using effect's (translated) name as the prefix
    // for the title.
    enum : long {
        DefaultMessageBoxStyle = wxOK | wxCENTRE
    };
    static int DoMessageBox(const EffectPlugin& plugin, const TranslatableString& message, long style = DefaultMessageBoxStyle,
                            const TranslatableString& titleStr = {});

    virtual ~EffectUIServices();

    //! The only non-const member function,
    //! it usually applies factory to plugin and self and given access
    /*!
     But there are a few unusual overrides for historical reasons that may ignore
     the factory.

     @param pInstance may be passed to factory, and is only guaranteed to have
     lifetime suitable for a modal dialog, unless the dialog stores a copy of
     pInstance

     @param access is only guaranteed to have lifetime suitable for a modal
     dialog, unless the dialog stores access.shared_from_this()

     @return 0 if destructive effect processing should not proceed (and there
     may be a non-modal dialog still opened); otherwise, modal dialog return code
     */
    virtual int ShowHostInterface(EffectBase& plugin, wxWindow& parent, const EffectDialogFactory& factory,
                                  std::shared_ptr<EffectInstance>& pInstance, EffectSettingsAccess& access, bool forceModal = false);

    /*!
     @return 0 if destructive effect processing should not proceed (and there
     may be a non-modal dialog still opened); otherwise, modal dialog return code
     */
    virtual int ShowClientInterface(const EffectPlugin& plugin, wxWindow& parent, wxDialog& dialog, EffectEditor* pEditor,
                                    bool forceModal = false) const = 0;

    //! Adds controls to a panel that is given as the parent window of `S`
    /*!
     @param S interface for adding controls to a panel in a dialog
     @param instance guaranteed to have a lifetime containing that of the returned
     object
     @param access guaranteed to have a lifetime containing that of the returned
     object
     @param pOutputs null, or else points to outputs with lifetime containing
     that of the returned object

     @return null for failure; else an object invoked to retrieve values of UI
     controls; it might also hold some state needed to implement event handlers
     of the controls; it will exist only while the dialog continues to exist
     */
    virtual std::unique_ptr<EffectEditor> PopulateUI(
        const EffectPlugin& plugin, ShuttleGui& S, EffectInstance& instance, EffectSettingsAccess& access,
        const EffectOutputs* pOutputs) const = 0;

    virtual void ExportPresets(
        const EffectPlugin& plugin, const EffectSettings& settings) const = 0;
    //! @return nullopt for failure
    [[nodiscard]] virtual OptionalMessage ImportPresets(
        const EffectPlugin& plugin, EffectSettings& settings) const = 0;

    virtual void ShowOptions(const EffectPlugin& plugin) const = 0;

    virtual bool ValidateUI(
        const EffectPlugin& context, EffectSettings& settings) const = 0;
    virtual bool CloseUI() const = 0;
};

#endif
